#include "gui_init.h"
extern "C" 
{
    static int g_fb_normal = -1;
    //static int g_fb_mouse = -1;
    static struct fb_bitfield g_a32 = {24, 8, 0};
    static struct fb_bitfield g_r32 = {16, 8, 0};
    static struct fb_bitfield g_g32 = {8,  8, 0};
    static struct fb_bitfield g_b32 = {0,  8, 0};
    typedef struct {
        ot_vo_intf_sync intf_sync;
        td_u32 width;
        td_u32 height;
        td_u32 frame_rate;
    } sample_vo_sync_info;
    static sample_vo_sync_info g_vo_sample_sync_info[OT_VO_OUT_BUTT] = {
    { OT_VO_OUT_PAL,        720, 576, 25 },
    { OT_VO_OUT_NTSC,       720, 480, 30 },
    { OT_VO_OUT_960H_PAL,   960, 576, 25 },
    { OT_VO_OUT_960H_NTSC,  960, 480, 30 },

    { OT_VO_OUT_640x480_60,     640,  480,  60 },
    { OT_VO_OUT_480P60,         720,  480,  60 },
    { OT_VO_OUT_576P50,         720,  576,  50 },
    { OT_VO_OUT_800x600_60,     800,  600,  60 },
    { OT_VO_OUT_1024x768_60,    1024, 768,  60 },
    { OT_VO_OUT_720P50,         1280, 720,  50 },
    { OT_VO_OUT_720P60,         1280, 720,  60 },
    { OT_VO_OUT_1280x800_60,    1280, 800,  60 },
    { OT_VO_OUT_1280x1024_60,   1280, 1024, 60 },
    { OT_VO_OUT_1366x768_60,    1366, 768,  60 },
    { OT_VO_OUT_1400x1050_60,   1400, 1050, 60 },
    { OT_VO_OUT_1440x900_60,    1440, 900,  60 },
    { OT_VO_OUT_1680x1050_60,   1680, 1050, 60 },

    { OT_VO_OUT_1080P24,    1920, 1080, 24 },
    { OT_VO_OUT_1080P25,    1920, 1080, 25 },
    { OT_VO_OUT_1080P30,    1920, 1080, 30 },
    { OT_VO_OUT_1080I50,    1920, 1080, 25 },
    { OT_VO_OUT_1080I60,    1920, 1080, 30 },
    { OT_VO_OUT_1080P50,    1920, 1080, 50 },
    { OT_VO_OUT_1080P60,    1920, 1080, 60 },

    { OT_VO_OUT_1600x1200_60,   1600, 1200, 60 },
    { OT_VO_OUT_1920x1200_60,   1920, 1200, 60 },
    { OT_VO_OUT_1920x2160_30,   1920, 2160, 30 },
    { OT_VO_OUT_2560x1440_30,   2560, 1440, 30 },
    { OT_VO_OUT_2560x1440_60,   2560, 1440, 60 },
    { OT_VO_OUT_2560x1600_60,   2560, 1600, 60 },

    { OT_VO_OUT_3840x2160_24, 3840, 2160, 24 },
    { OT_VO_OUT_3840x2160_25, 3840, 2160, 25 },
    { OT_VO_OUT_3840x2160_30, 3840, 2160, 30 },
    { OT_VO_OUT_3840x2160_50, 3840, 2160, 50 },
    { OT_VO_OUT_3840x2160_60, 3840, 2160, 60 },
    { OT_VO_OUT_4096x2160_24, 4096, 2160, 24 },
    { OT_VO_OUT_4096x2160_25, 4096, 2160, 25 },
    { OT_VO_OUT_4096x2160_30, 4096, 2160, 30 },
    { OT_VO_OUT_4096x2160_50, 4096, 2160, 50 },
    { OT_VO_OUT_4096x2160_60, 4096, 2160, 60 },
    { OT_VO_OUT_7680x4320_30, 7680, 4320, 30 },

    { OT_VO_OUT_240x320_50, 240, 320, 50 },
    { OT_VO_OUT_320x240_50, 320, 240, 50 },
    { OT_VO_OUT_240x320_60, 240, 320, 60 },
    { OT_VO_OUT_320x240_60, 320, 240, 60 },
    { OT_VO_OUT_800x600_50, 800, 600, 50 },

    { OT_VO_OUT_720x1280_60, 720, 1280, 60 },
    { OT_VO_OUT_1080x1920_60, 1080, 1920, 60 },
    { OT_VO_OUT_USER,  0,    0,    0 }
};

    static const ot_hdmi_video_format g_vo_hdmi_sync[OT_VO_OUT_BUTT] = {
        OT_HDMI_VIDEO_FORMAT_PAL,
        OT_HDMI_VIDEO_FORMAT_NTSC,
        OT_HDMI_VIDEO_FORMAT_VESA_CUSTOMER_DEFINE,
        OT_HDMI_VIDEO_FORMAT_VESA_CUSTOMER_DEFINE,
        OT_HDMI_VIDEO_FORMAT_861D_640X480_60,
        OT_HDMI_VIDEO_FORMAT_480P_60,
        OT_HDMI_VIDEO_FORMAT_576P_50,
        OT_HDMI_VIDEO_FORMAT_VESA_800X600_60,
        OT_HDMI_VIDEO_FORMAT_VESA_1024X768_60,
        OT_HDMI_VIDEO_FORMAT_720P_50,
        OT_HDMI_VIDEO_FORMAT_720P_60,
        OT_HDMI_VIDEO_FORMAT_VESA_1280X800_60,
        OT_HDMI_VIDEO_FORMAT_VESA_1280X1024_60,
        OT_HDMI_VIDEO_FORMAT_VESA_1366X768_60,
        OT_HDMI_VIDEO_FORMAT_VESA_1400X1050_60,
        OT_HDMI_VIDEO_FORMAT_VESA_1440X900_60,
        OT_HDMI_VIDEO_FORMAT_VESA_1680X1050_60,
        OT_HDMI_VIDEO_FORMAT_1080P_24,
        OT_HDMI_VIDEO_FORMAT_1080P_25,
        OT_HDMI_VIDEO_FORMAT_1080P_30,
        OT_HDMI_VIDEO_FORMAT_1080i_50,
        OT_HDMI_VIDEO_FORMAT_1080i_60,
        OT_HDMI_VIDEO_FORMAT_1080P_50,
        OT_HDMI_VIDEO_FORMAT_1080P_60,
        OT_HDMI_VIDEO_FORMAT_VESA_1600X1200_60,
        OT_HDMI_VIDEO_FORMAT_VESA_1920X1200_60,
        OT_HDMI_VIDEO_FORMAT_1920x2160_30,
        OT_HDMI_VIDEO_FORMAT_2560x1440_30,
        OT_HDMI_VIDEO_FORMAT_2560x1440_60,
        OT_HDMI_VIDEO_FORMAT_2560x1600_60,
        OT_HDMI_VIDEO_FORMAT_3840X2160P_24,
        OT_HDMI_VIDEO_FORMAT_3840X2160P_25,
        OT_HDMI_VIDEO_FORMAT_3840X2160P_30,
        OT_HDMI_VIDEO_FORMAT_3840X2160P_50,
        OT_HDMI_VIDEO_FORMAT_3840X2160P_60,
        OT_HDMI_VIDEO_FORMAT_4096X2160P_24,
        OT_HDMI_VIDEO_FORMAT_4096X2160P_25,
        OT_HDMI_VIDEO_FORMAT_4096X2160P_30,
        OT_HDMI_VIDEO_FORMAT_4096X2160P_50,
        OT_HDMI_VIDEO_FORMAT_4096X2160P_60,
        OT_HDMI_VIDEO_FORMAT_7680X4320P_30,
        OT_HDMI_VIDEO_FORMAT_VESA_CUSTOMER_DEFINE,
        OT_HDMI_VIDEO_FORMAT_VESA_CUSTOMER_DEFINE,
        OT_HDMI_VIDEO_FORMAT_VESA_CUSTOMER_DEFINE,
        OT_HDMI_VIDEO_FORMAT_VESA_CUSTOMER_DEFINE,
        OT_HDMI_VIDEO_FORMAT_VESA_CUSTOMER_DEFINE,
        OT_HDMI_VIDEO_FORMAT_VESA_CUSTOMER_DEFINE,
        OT_HDMI_VIDEO_FORMAT_VESA_CUSTOMER_DEFINE,
        OT_HDMI_VIDEO_FORMAT_VESA_CUSTOMER_DEFINE,
    };

    static td_void vo_hdmi_convert_sync(ot_vo_intf_sync intf_sync, ot_hdmi_video_format *video_fmt)
    {
        *video_fmt = OT_HDMI_VIDEO_FORMAT_1080P_60;
        if ((intf_sync >= OT_VO_OUT_PAL) && (intf_sync < OT_VO_OUT_BUTT))
        {
            *video_fmt = g_vo_hdmi_sync[intf_sync];
        }
    }

    static void vo_hdmi_stop()
    {
        ot_hdmi_id hdmi_id = OT_HDMI_ID_0;
        ss_mpi_hdmi_stop(hdmi_id);
        ss_mpi_hdmi_close(hdmi_id);
        ss_mpi_hdmi_deinit();
    }

    static td_s32 vo_hdmi_start(ot_vo_intf_sync intf_sync)
    {
        ot_hdmi_attr attr;
        ot_hdmi_video_format video_fmt;
        ot_hdmi_id hdmi_id = OT_HDMI_ID_0;
        td_s32 ret;

        vo_hdmi_convert_sync(intf_sync, &video_fmt);

        ret = ss_mpi_hdmi_init();
        if(ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_hdmi_init failed with:%x\n",__FUNCTION__,ret);
            return -1;
        }

        ret = ss_mpi_hdmi_open(hdmi_id);
        if(ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_hdmi_open failed with:%x\n",__FUNCTION__,ret);
            return -1;
        }

        ret = ss_mpi_hdmi_get_attr(hdmi_id,&attr);
        if(ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_hdmi_get_attr failed with:%x\n",__FUNCTION__,ret);
            return -1;
        }
        attr.video_format = video_fmt;
        ret = ss_mpi_hdmi_set_attr(hdmi_id,&attr);
        if(ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_hdmi_set_attr failed with:%x\n",__FUNCTION__,ret);
            return -1;
        }

        ret = ss_mpi_hdmi_start(hdmi_id);
        if(ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_hdmi_start failed with:%x\n",__FUNCTION__,ret);
            return -1;
        }

        return 0;
    }

    static int show_fb(int fb_fd,
            ot_fb_point* ppoint,
            struct fb_bitfield bit_a,
            struct fb_bitfield bit_r,
            struct fb_bitfield bit_g,
            struct fb_bitfield bit_b,
            int xres,
            int yres,
            int xres_virtual,
            int yres_virtual)
    {
        int ret;

        td_bool show = TD_FALSE;
        ret = ioctl(fb_fd, FBIOPUT_SHOW_GFBG, &show);
        if(ret < 0)
        {
            printf("[%s]: show gfbg failed\n",__FUNCTION__);
            return -1;
        }

        ret = ioctl(fb_fd, FBIOPUT_SCREEN_ORIGIN_GFBG, ppoint);
        if(ret < 0)
        {
            printf("[%s]: show screen_origin_gfbg failed\n",__FUNCTION__);
            return -1;
        }

        struct fb_var_screeninfo var;
        ret = ioctl(fb_fd, FBIOGET_VSCREENINFO, &var);
        if(ret < 0)
        {
            printf("[%s]: show FBIOGET_VSCREENINFO failed\n",__FUNCTION__);
            return -1;
        }

        var.transp = bit_a;
        var.red = bit_r;
        var.green = bit_g;
        var.blue = bit_b;
        var.bits_per_pixel = 32; /* 32 for 4 byte */
        var.xres_virtual = xres_virtual;
        var.yres_virtual = yres_virtual;
        var.xres = xres;
        var.yres = yres;
        var.activate = FB_ACTIVATE_NOW;
        ret = ioctl(fb_fd, FBIOPUT_VSCREENINFO, &var);
        if(ret < 0)
        {
            printf("[%s]: show FBIOPUT_VSCREENINFO failed\n",__FUNCTION__);
            return -1;
        }
        
        show = TD_TRUE;
        ret = ioctl(fb_fd, FBIOPUT_SHOW_GFBG, &show);
        if(ret < 0)
        {
            printf("[%s]: show gfbg failed\n",__FUNCTION__);
            return -1;
        }

        ot_fb_alpha alpha;
        memset(&alpha,0,sizeof(alpha));
        alpha.alpha_en = TD_FALSE;
        alpha.alpha0 = 0x0;
        alpha.alpha1 = 0xff;
        ret = ioctl(fb_fd, FBIOPUT_ALPHA_GFBG,  &alpha);
        if(ret < 0)
        {
            printf("[%s]: FBIOPUT_ALPHA_GFBG failed\n",__FUNCTION__);
            return -1;
        }

#if 0
        ot_fb_colorkey color_key;
        memset(&color_key,0,sizeof(color_key));
        color_key.enable = TD_FALSE;
        color_key.value = 0xFFff0000;//red
        ret = ioctl(fb_fd, FBIOPUT_COLORKEY_GFBG, &color_key);
        if(ret < 0)
        {
            printf("[%s]: FBIOPUT_COLORKEY_GFBG failed\n",__FUNCTION__);
            return -1;
        }

        ot_fb_layer_info layer_info;
        memset(&layer_info,0,sizeof(layer_info));
        layer_info.buf_mode = OT_FB_LAYER_BUF_DOUBLE;
        layer_info.mask = OT_FB_LAYER_MASK_BUF_MODE;
        ret = ioctl(fb_fd, FBIOPUT_LAYER_INFO, &layer_info);
        if(ret < 0)
        {
            printf("[%s]: FBIOPUT_LAYER_INFO failed\n",__FUNCTION__);
            return -1;
        }
#endif

        return 0;
    }

    int gui_init(gui_cfg_t* cfg)
    {
        td_s32 ret;
        ot_vb_cfg vb_cfg;
        ot_fb_point point =  {0,0};
        ot_vo_pub_attr pub_attr;
        int screen_w,screen_h;

        //step1: vb init
        ss_mpi_sys_exit();
        ss_mpi_vb_exit();

        memset(&vb_cfg,0,sizeof(ot_vb_cfg));
        vb_cfg.common_pool[0].blk_size = 3840 * 2160 * 2;
        vb_cfg.common_pool[0].blk_cnt = 20;
        vb_cfg.common_pool[1].blk_size = 704 * 576 * 3 / 2;
        vb_cfg.common_pool[1].blk_cnt = 10;
        vb_cfg.max_pool_cnt= 2;
        ret = ss_mpi_vb_set_cfg(&vb_cfg);
        if(ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_vb_set_cfg failed with:%x\n",__FUNCTION__,ret);
            return -1;
        }

        ot_vb_supplement_cfg vb_supplement_cfg = {0};
        vb_supplement_cfg.supplement_cfg = OT_VB_SUPPLEMENT_BNR_MOT_MASK;
        ret = ss_mpi_vb_set_supplement_cfg(&vb_supplement_cfg);
        if (ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_vb_set_supplement_cfg failed with:%x\n",__FUNCTION__,ret);
            return -1;
        }

        ret = ss_mpi_vb_init();
        if(ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_vb_init failed with:%x\n",__FUNCTION__,ret);
            return -1;
        }

        ret = ss_mpi_sys_init();
        if(ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_sys_init failed with:%x\n",__FUNCTION__,ret);
            goto ERR1;
        }

        //step2: enable vo
        memset(&pub_attr,0,sizeof(pub_attr));
        pub_attr.intf_type = cfg->vo_intf_type;
        pub_attr.intf_sync = cfg->vo_intf_sync;
        pub_attr.bg_color = cfg->vo_bg_color;
        ret = ss_mpi_vo_set_pub_attr(cfg->vo_dev,&pub_attr);
        if(ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_vo_set_pub_attr failed with:%x\n",__FUNCTION__,ret);
            goto ERR1;
        }
        ret = ss_mpi_vo_enable(cfg->vo_dev);
        if(ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_vo_enable failed with:%x\n",__FUNCTION__,ret);
            goto ERR1;
        }

        //step3:bind G3 to VO device
        ss_mpi_vo_unbind_layer(OT_VO_LAYER_G3,cfg->vo_dev);
        ret = ss_mpi_vo_bind_layer(OT_VO_LAYER_G3,cfg->vo_dev);
        if(ret != TD_SUCCESS)
        {
            printf("[%s]: ss_mpi_vo_bind layer failed with:%x\n",__FUNCTION__,ret);
            goto ERR2;
        }

        //step4:start hdmi
        //only support hdmi now
        if(cfg->vo_intf_type == OT_VO_INTF_HDMI)
        {
            ret = vo_hdmi_start(cfg->vo_intf_sync);
            if(ret < 0)
            {
                printf("[%s]: vo_hdmi_start failed \n",__FUNCTION__);
                goto ERR2;
            }
        }

        //step5: fb init
        //fb for gui
        screen_w = g_vo_sample_sync_info[cfg->vo_intf_sync].width;
        screen_h = g_vo_sample_sync_info[cfg->vo_intf_sync].height;
        printf("screen_w:%d,screen_h:%d\n",screen_w,screen_h);
        g_fb_normal = open(cfg->fb_normal_path,O_RDWR,0);
        if(g_fb_normal < 0)
        {
            printf("[%s]: open %s failed\n",__FUNCTION__,cfg->fb_normal_path);
            goto ERR3;
        }
        ret = show_fb(g_fb_normal,
                &point,
                g_a32,
                g_r32,
                g_g32,
                g_b32,
                screen_w,
                screen_h,
                screen_w,
                screen_h * 2);

#if 0
        //fb for mouse
        point.x_pos = 150;
        point.y_pos = 150;
        g_fb_mouse = open(cfg->fb_mouse_path,O_RDWR,0);
        if(g_fb_mouse < 0)
        {
            printf("[%s]: open %s failed\n",__FUNCTION__,cfg->fb_mouse_path);
            goto ERR3;
        }

        ret = show_fb(g_fb_mouse,
                &point,
                g_a32,
                g_r32,
                g_g32,
                g_b32,
                48,
                48,
                48,
                48);
        if(ret < 0)
        {
            goto ERR3;
        }
#endif

        return 0;

ERR3: 
        vo_hdmi_stop();         
ERR2: 
        ss_mpi_vo_disable(cfg->vo_dev);
ERR1:
        ss_mpi_sys_exit();
        ss_mpi_vb_exit();
        return -1;
    }

    int gui_release()
    {
        if(g_fb_normal > -1)
        {
            close(g_fb_normal);
            g_fb_normal = -1;
        }

#if 0
        if(g_fb_mouse > -1)
        {
            close(g_fb_mouse);
            g_fb_mouse = -1;
        }
#endif

        vo_hdmi_stop();         
        for(int i = 0; i < 2; i++)
        {
            ss_mpi_vo_disable(i);
        }
        ss_mpi_sys_exit();
        ss_mpi_vb_exit();
        return 0;
    }
}
